home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / rcs / part10 < prev    next >
Encoding:
Internet Message Format  |  1991-03-05  |  53.3 KB

  1. Subject:  v24i010:  RCS source control system, Part10/12
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 1d181017 1c0fdd37 3174ca6e 201ae133
  5.  
  6. Submitted-by: Adam Hammer <hammer@cs.purdue.edu>
  7. Posting-number: Volume 24, Issue 10
  8. Archive-name: rcs/part10
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  man/rcsintro.1 rcs_func.ms src/maketime.c src/rcsdiff.c
  17. #   src/rcskeep.c src/rcsmerge.c
  18. # Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:37:09 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. echo If this archive is complete, you will see the following message:
  21. echo '          "shar: End of archive 10 (of 12)."'
  22. if test -f 'man/rcsintro.1' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'man/rcsintro.1'\"
  24. else
  25.   echo shar: Extracting \"'man/rcsintro.1'\" \(9209 characters\)
  26.   sed "s/^X//" >'man/rcsintro.1' <<'END_OF_FILE'
  27. X.de Id
  28. X.ds Rv \\$3
  29. X.ds Dt \\$4
  30. X..
  31. X.Id $Id: rcsintro.1,v 5.0 1990/08/22 09:11:00 eggert Exp $
  32. X.ds r \s-1RCS\s0
  33. X.if n .ds - \%--
  34. X.if t .ds - \(em
  35. X.am SS
  36. X.LP
  37. X..
  38. X.TH RCSINTRO 1 \*(Dt GNU
  39. X.SH NAME
  40. Xrcsintro \- introduction to RCS commands
  41. X.SH DESCRIPTION
  42. XThe Revision Control System (\*r) manages multiple revisions of files.
  43. X\*r automates the storing, retrieval, logging, identification, and merging
  44. Xof revisions.  \*r is useful for text that is revised frequently, for example
  45. Xprograms, documentation, graphics, papers, and form letters.
  46. X.PP
  47. XThe basic user interface is extremely simple.  The novice only needs
  48. Xto learn two commands:
  49. X.BR ci (1)
  50. Xand
  51. X.BR co (1).
  52. X.BR ci ,
  53. Xshort for \*(lqcheck in\*(rq, deposits the contents of a
  54. Xfile into an archival file called an \*r file.  An \*r file
  55. Xcontains all revisions of a particular file.
  56. X.BR co ,
  57. Xshort for \*(lqcheck out\*(rq, retrieves revisions from an \*r file.
  58. X.SS "Functions of \*r"
  59. X.IP \(bu
  60. XStore and retrieve multiple revisions of text.  \*r saves all old
  61. Xrevisions in a space efficient way.
  62. XChanges no longer destroy the original, because the
  63. Xprevious revisions remain accessible.  Revisions can be retrieved according to
  64. Xranges of revision numbers, symbolic names, dates, authors, and
  65. Xstates.
  66. X.IP \(bu
  67. XMaintain a complete history of changes.
  68. X\*r logs all changes automatically.
  69. XBesides the text of each revision, \*r stores the author, the date and time of
  70. Xcheck-in, and a log message summarizing the change.
  71. XThe logging makes it easy to find out
  72. Xwhat happened to a module, without having to compare
  73. Xsource listings or having to track down colleagues.
  74. X.IP \(bu
  75. XResolve access conflicts.  When two or more programmers wish to
  76. Xmodify the same revision, \*r alerts the programmers and prevents one
  77. Xmodification from corrupting the other.
  78. X.IP \(bu
  79. XMaintain a tree of revisions.  \*r can maintain separate lines of development
  80. Xfor each module.  It stores a tree structure that represents the
  81. Xancestral relationships among revisions.
  82. X.IP \(bu
  83. XMerge revisions and resolve conflicts.
  84. XTwo separate lines of development of a module can be coalesced by merging.
  85. XIf the revisions to be merged affect the same sections of code, \*r alerts the
  86. Xuser about the overlapping changes.
  87. X.IP \(bu
  88. XControl releases and configurations.
  89. XRevisions can be assigned symbolic names
  90. Xand marked as released, stable, experimental, etc.
  91. XWith these facilities, configurations of modules can be
  92. Xdescribed simply and directly.
  93. X.IP \(bu
  94. XAutomatically identify each revision with name, revision number,
  95. Xcreation time, author, etc.
  96. XThe identification is like a stamp that can be embedded at an appropriate place
  97. Xin the text of a revision.
  98. XThe identification makes it simple to determine which
  99. Xrevisions of which modules make up a given configuration.
  100. X.IP \(bu
  101. XMinimize secondary storage.  \*r needs little extra space for
  102. Xthe revisions (only the differences).  If intermediate revisions are
  103. Xdeleted, the corresponding deltas are compressed accordingly.
  104. X.SS "Getting Started with \*r"
  105. XSuppose you have a file
  106. X.B f.c
  107. Xthat you wish to put under control of \*r.
  108. XInvoke the check-in command
  109. X.IP
  110. X.B "ci  f.c"
  111. X.LP
  112. XThis command creates the \*r file
  113. X.BR f.c,v ,
  114. Xstores
  115. X.B f.c
  116. Xinto it as revision 1.1, and
  117. Xdeletes
  118. X.BR f.c .
  119. XIt also asks you for a description.  The description
  120. Xshould be a synopsis of the contents of the file.  All later check-in
  121. Xcommands will ask you for a log entry, which should summarize the
  122. Xchanges that you made.
  123. X.PP
  124. XFiles ending in
  125. X.B ,v
  126. Xare called \*r files (\*(lqv\*(rq stands for \*(lqversions\*(rq);
  127. Xthe others are called working files.
  128. XTo get back the working file
  129. X.B f.c
  130. Xin the previous example, use the check-out
  131. Xcommand
  132. X.IP
  133. X.B "co  f.c"
  134. X.LP
  135. XThis command extracts the latest revision from
  136. X.B f.c,v
  137. Xand writes
  138. Xit into
  139. X.BR f.c .
  140. XIf you want to edit
  141. X.BR f.c ,
  142. Xyou must lock it as you check it out with the command
  143. X.IP
  144. X.B "co  \-l  f.c"
  145. X.LP
  146. XYou can now edit
  147. X.BR f.c .
  148. X.PP
  149. XSuppose after some editing you want to know what changes that you have made.
  150. XThe command
  151. X.IP
  152. X.B "rcsdiff  f.c"
  153. X.LP
  154. Xtells you the difference between the most recently checked-in version
  155. Xand the working file.
  156. XYou can check the file back in by invoking
  157. X.IP
  158. X.B "ci  f.c"
  159. X.LP
  160. XThis increments the revision number properly.
  161. X.PP
  162. XIf
  163. X.B ci
  164. Xcomplains with the message
  165. X.IP
  166. X.BI "ci error: no lock set by " "your name"
  167. X.LP
  168. Xthen you have tried to check in a file even though you did not
  169. Xlock it when you checked it out.
  170. XOf course, it is too late now to do the check-out with locking, because
  171. Xanother check-out would
  172. Xoverwrite your modifications.  Instead, invoke
  173. X.IP
  174. X.B "rcs  \-l  f.c"
  175. X.LP
  176. XThis command will lock the latest revision for you, unless somebody
  177. Xelse got ahead of you already.  In this case, you'll have to negotiate with
  178. Xthat person.
  179. X.PP
  180. XLocking assures that you, and only you, can check in the next update, and
  181. Xavoids nasty problems if several people work on the same file.
  182. XEven if a revision is locked, it can still be checked out for
  183. Xreading, compiling, etc.  All that locking
  184. Xprevents is a
  185. X.I "check-in"
  186. Xby anybody but the locker.
  187. X.PP
  188. XIf your \*r file is private, i.e., if you are the only person who is going
  189. Xto deposit revisions into it, strict locking is not needed and you
  190. Xcan turn it off.
  191. XIf strict locking is turned off,
  192. Xthe owner of the \*r file need not have a lock for check-in; all others
  193. Xstill do.  Turning strict locking off and on is done with the commands
  194. X.IP
  195. X.BR "rcs  \-U  f.c" "     and     " "rcs  \-L  f.c"
  196. X.LP
  197. XIf you don't want to clutter your working directory with \*r files, create
  198. Xa subdirectory called
  199. X.B RCS
  200. Xin your working directory, and move all your \*r
  201. Xfiles there.  \*r commands will look first into that directory to find
  202. Xneeded files.  All the commands discussed above will still work, without any
  203. Xmodification.
  204. X(Actually, pairs of \*r and working files can be specified in three ways:
  205. X(a) both are given, (b) only the working file is given, (c) only the
  206. X\*r file is given.  Both \*r and working files may have arbitrary path prefixes;
  207. X\*r commands pair them up intelligently.)
  208. X.PP
  209. XTo avoid the deletion of the working file during check-in (in case you want to
  210. Xcontinue editing or compiling), invoke
  211. X.IP
  212. X.BR "ci  \-l  f.c" "     or     " "ci  \-u  f.c"
  213. X.LP
  214. XThese commands check in
  215. X.B f.c
  216. Xas usual, but perform an implicit
  217. Xcheck-out.  The first form also locks the checked in revision, the second one
  218. Xdoesn't.  Thus, these options save you one check-out operation.
  219. XThe first form is useful if you want to continue editing,
  220. Xthe second one if you just want to read the file.
  221. XBoth update the identification markers in your working file (see below).
  222. X.PP
  223. XYou can give
  224. X.B ci
  225. Xthe number you want assigned to a checked in
  226. Xrevision.  Assume all your revisions were numbered 1.1, 1.2, 1.3, etc.,
  227. Xand you would like to start release 2.
  228. XThe command
  229. X.IP
  230. X.BR "ci  \-r2  f.c" "     or     " "ci  \-r2.1  f.c"
  231. X.LP
  232. Xassigns the number 2.1 to the new revision.
  233. XFrom then on,
  234. X.B ci
  235. Xwill number the subsequent revisions
  236. Xwith 2.2, 2.3, etc.  The corresponding
  237. X.B co
  238. Xcommands
  239. X.IP
  240. X.BR "co  \-r2  f.c" "     and     " "co  \-r2.1  f.c"
  241. X.PP
  242. Xretrieve the latest revision numbered
  243. X.RI 2. x
  244. Xand the revision 2.1,
  245. Xrespectively.
  246. X.B co
  247. Xwithout a revision number selects
  248. Xthe latest revision on the
  249. X.IR trunk ,
  250. Xi.e. the highest
  251. Xrevision with a number consisting of two fields.  Numbers with more than two
  252. Xfields are needed for branches.
  253. XFor example, to start a branch at revision 1.3, invoke
  254. X.IP
  255. X.B "ci  \-r1.3.1  f.c"
  256. X.LP
  257. XThis command starts a branch numbered 1 at revision 1.3, and assigns
  258. Xthe number 1.3.1.1 to the new revision.  For more information about
  259. Xbranches, see
  260. X.BR rcsfile (5).
  261. X.SS "Automatic Identification"
  262. X\*r can put special strings for identification into your source and object
  263. Xcode.  To obtain such identification, place the marker
  264. X.IP
  265. X.B "$\&Id$"
  266. X.LP
  267. Xinto your text, for instance inside a comment.
  268. X\*r will replace this marker with a string of the form
  269. X.IP
  270. X.BI $\&Id: "  filename  revision  date  time  author  state  " $
  271. X.LP
  272. XWith such a marker on the first page of each module, you can
  273. Xalways see with which revision you are working.
  274. X\*r keeps the markers up to date automatically.
  275. XTo propagate the markers into your object code, simply put
  276. Xthem into literal character strings.  In C, this is done as follows:
  277. X.IP
  278. X.ft 3
  279. Xstatic char rcsid[] = \&"$\&Id$\&";
  280. X.ft
  281. X.LP
  282. XThe command
  283. X.B ident
  284. Xextracts such markers from any file, even object code
  285. Xand dumps.
  286. XThus,
  287. X.B ident
  288. Xlets you find out
  289. Xwhich revisions of which modules were used in a given program.
  290. X.PP
  291. XYou may also find it useful to put the marker
  292. X.B $\&Log$
  293. Xinto your text, inside a comment.  This marker accumulates
  294. Xthe log messages that are requested during check-in.
  295. XThus, you can maintain the complete history of your file directly inside it.
  296. XThere are several additional identification markers; see
  297. X.BR co (1)
  298. Xfor
  299. Xdetails.
  300. X.SH IDENTIFICATION
  301. XAuthor: Walter F. Tichy.
  302. X.br
  303. XRevision Number: \*(Rv; Release Date: \*(Dt.
  304. X.br
  305. XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
  306. X.br
  307. XCopyright \(co 1990 by Paul Eggert.
  308. X.SH "SEE ALSO"
  309. Xci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1)
  310. X.br
  311. XWalter F. Tichy,
  312. X\*r\*-A System for Version Control,
  313. X.I "Software\*-Practice & Experience"
  314. X.BR 15 ,
  315. X7 (July 1985), 637-654.
  316. END_OF_FILE
  317.   if test 9209 -ne `wc -c <'man/rcsintro.1'`; then
  318.     echo shar: \"'man/rcsintro.1'\" unpacked with wrong size!
  319.   fi
  320.   # end of 'man/rcsintro.1'
  321. fi
  322. if test -f 'rcs_func.ms' -a "${1}" != "-c" ; then 
  323.   echo shar: Will not clobber existing file \"'rcs_func.ms'\"
  324. else
  325.   echo shar: Extracting \"'rcs_func.ms'\" \(3683 characters\)
  326.   sed "s/^X//" >'rcs_func.ms' <<'END_OF_FILE'
  327. X.SH
  328. XFunctions of RCS (Revision Control System)
  329. X.PP
  330. XRCS manages software libraries. It greatly increases programmer productivity
  331. Xby providing the following functions.
  332. X.IP 1.
  333. XRCS stores and retrieves multiple revisions of program and other text.
  334. XThus, one can maintain one or more releases while developing the next
  335. Xrelease, with a minimum of space overhead. Changes no longer destroy the
  336. Xoriginal -- previous revisions remain accessible.
  337. X.RS
  338. X.IP a.
  339. XMaintains each module as a tree of revisions.
  340. X.IP b.
  341. XProject libraries can
  342. Xbe organized centrally, decentralized, or any way you like.
  343. X.IP c.
  344. XRCS works for any type of text: programs, documentation, memos, papers,
  345. Xgraphics, VLSI layouts, form letters, etc.
  346. X.RE
  347. X.IP 2.
  348. XRCS maintains a complete history of changes.
  349. XThus, one can find out what happened to a module easily
  350. Xand quickly, without having to compare source listings or
  351. Xhaving to track down colleagues.
  352. X.RS
  353. X.IP a.
  354. XRCS performs automatic record keeping.
  355. X.IP b.
  356. XRCS logs all changes automatically.
  357. X.IP c.
  358. XRCS guarantees project continuity.
  359. X.RE
  360. X.IP 3.
  361. XRCS manages multiple lines of development.
  362. X.IP 4.
  363. XRCS can merge multiple lines of development.
  364. XThus, when several parallel lines of development must be consolidated
  365. Xinto one line, the merging of changes is automatic.
  366. X.IP 5.
  367. XRCS flags coding conflicts.
  368. XIf two or more lines of development modify the same section of code,
  369. XRCS can alert programmers about overlapping changes.
  370. X.IP 6.
  371. XRCS resolves access conflicts.
  372. XWhen two or more programmers wish to modify the same revision,
  373. XRCS alerts the programmers and makes sure that one modification won't wipe
  374. Xout the other one.
  375. X.IP 7.
  376. XRCS provides high-level retrieval functions.
  377. XRevisions can be retrieved according to ranges of revision numbers,
  378. Xsymbolic names, dates, authors, and states.
  379. X.IP 8.
  380. XRCS provides release and configuration control.
  381. XRevisions can be marked as released, stable, experimental, etc.
  382. XConfigurations of modules can be described simply and directly.
  383. X.IP 9.
  384. XRCS performs automatic identification of modules with name, revision
  385. Xnumber, creation time, author, etc.
  386. XThus, it is always possible to determine which revisions of which
  387. Xmodules make up a given configuration.
  388. X.IP 10.
  389. XProvides high-level management visibility.
  390. XThus, it is easy to track the status of a software project.
  391. X.RS
  392. X.IP a.
  393. XRCS provides a complete change history.
  394. X.IP b.
  395. XRCS records who did what when to which revision of which module.
  396. X.RE
  397. X.IP 11.
  398. XRCS is fully compatible with existing software development tools.
  399. XRCS is unobtrusive -- its interface to the file system is such that
  400. Xall your existing software tools can be used as before.
  401. X.IP 12.
  402. XRCS' basic user interface is extremely simple. The novice need to learn
  403. Xonly two commands. Its more sophisticated features have been
  404. Xtuned towards advanced software development environments and the
  405. Xexperienced software professional.
  406. X.IP 13.
  407. XRCS simplifies software distribution if customers
  408. Xmaintain sources with RCS also. This technique assures proper
  409. Xidentification of versions and configurations, and tracking of customer
  410. Xmodifications. Customer modifications can be merged into distributed
  411. Xversions locally or by the development group.
  412. X.IP 14.
  413. XRCS needs little extra space for the revisions (only the differences).
  414. XIf intermediate revisions are deleted, the corresponding
  415. Xdifferences are compressed into the shortest possible form.
  416. X.IP 15.
  417. XRCS is implemented with reverse deltas. This means that
  418. Xthe latest revision, which is the one that is accessed most often,
  419. Xis stored intact. All others are regenerated from the latest one
  420. Xby applying reverse deltas (backward differences). This
  421. Xresults in fast access time for the revision needed most often.
  422. END_OF_FILE
  423.   if test 3683 -ne `wc -c <'rcs_func.ms'`; then
  424.     echo shar: \"'rcs_func.ms'\" unpacked with wrong size!
  425.   fi
  426.   # end of 'rcs_func.ms'
  427. fi
  428. if test -f 'src/maketime.c' -a "${1}" != "-c" ; then 
  429.   echo shar: Will not clobber existing file \"'src/maketime.c'\"
  430. else
  431.   echo shar: Extracting \"'src/maketime.c'\" \(8733 characters\)
  432.   sed "s/^X//" >'src/maketime.c' <<'END_OF_FILE'
  433. X#
  434. X/*
  435. X * MAKETIME        derive 32-bit time value from TM structure.
  436. X *
  437. X * Usage:
  438. X *    int zone;    Minutes west of GMT, or
  439. X *            48*60 for localtime
  440. X *    time_t t;
  441. X *    struct tm *tp;    Pointer to TM structure from <time.h>
  442. X *    t = maketime(tp,zone);
  443. X *
  444. X * Returns:
  445. X *    -1 if failure; parameter out of range or nonsensical.
  446. X *    else time-value.
  447. X * Notes:
  448. X *    This code is quasi-public; it may be used freely in like software.
  449. X *    It is not to be sold, nor used in licensed software without
  450. X *    permission of the author.
  451. X *    For everyone's benefit, please report bugs and improvements!
  452. X *     Copyright 1981 by Ken Harrenstien, SRI International.
  453. X *    (ARPANET: KLH @ SRI)
  454. X */
  455. X/* $Log: maketime.c,v $
  456. X * Revision 5.2  1990/11/01  05:03:30  eggert
  457. X * Remove lint.
  458. X *
  459. X * Revision 5.1  1990/10/04  06:30:13  eggert
  460. X * Calculate the GMT offset of 'xxx LT' as of xxx, not as of now.
  461. X * Don't assume time_t is 32 bits.  Fix bugs near epoch and near end of time.
  462. X *
  463. X * Revision 5.0  1990/08/22  08:12:38  eggert
  464. X * Switch to GMT and fix the bugs exposed thereby.
  465. X * Permit dates past 1999/12/31.  Ansify and Posixate.
  466. X *
  467. X * Revision 1.8  88/11/08  13:54:53  narten
  468. X * allow negative timezones (-24h <= x <= 24h)
  469. X * 
  470. X * Revision 1.7  88/08/28  14:47:52  eggert
  471. X * Allow cc -R.  Remove unportable "#endif XXX"s.
  472. X * 
  473. X * Revision 1.6  87/12/18  17:05:58  narten
  474. X * include rcsparam.h
  475. X * 
  476. X * Revision 1.5  87/12/18  11:35:51  narten
  477. X * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
  478. X * "timezone" set. ("localtime" calls it, but it's probably better not to 
  479. X * count on "localtime" having been called.)
  480. X * 
  481. X * Revision 1.4  87/10/18  10:26:57  narten
  482. X * Updating version numbers. Changes relative to 1.0 are actually 
  483. X * relative to 1.2
  484. X * 
  485. X * Revision 1.3  87/09/24  13:58:45  narten
  486. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  487. X * warnings)
  488. X * 
  489. X * Revision 1.2  87/03/27  14:21:48  jenkins
  490. X * Port to suns
  491. X * 
  492. X * Revision 1.2  83/12/05  10:12:56  wft
  493. X * added cond. compilation for USG Unix; long timezone;
  494. X * 
  495. X * Revision 1.1  82/05/06  11:38:00  wft
  496. X * Initial revision
  497. X * 
  498. X */
  499. X
  500. X
  501. X#include "rcsbase.h"
  502. X
  503. XlibId(maketId, "$Id: maketime.c,v 5.2 1990/11/01 05:03:30 eggert Exp $")
  504. X
  505. Xstatic const struct tm *time2tm P((time_t));
  506. X
  507. X#define given(v) (0 <= (v)) /* Negative values are unspecified. */
  508. X
  509. Xstatic const int daytb[] = {
  510. X    /* # days in year thus far, indexed by month (0-12!!) */
  511. X    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  512. X};
  513. X
  514. X    static time_t
  515. Xmaketime(atm,zone)
  516. X    const struct tm *atm;
  517. X    int zone;
  518. X{
  519. X    register const struct tm *tp;
  520. X    register int i;
  521. X    int year, yday, mon, day, hour, min, sec, leap, localzone;
  522. X    int attempts;
  523. X    time_t t, tres;
  524. X
  525. X    attempts = 2;
  526. X    localzone = zone==48*60;
  527. X    tres = -1;
  528. X    year = mon = day = 0;  /* Keep lint happy.  */
  529. X
  530. X    do {
  531. X
  532. X    if (localzone || !given(atm->tm_year)) {
  533. X        if (tres == -1)
  534. X            if ((tres = time((time_t*)0))  ==  -1)
  535. X                return -1;
  536. X        tp = time2tm(tres);
  537. X        /* Get breakdowns of default time, adjusting to zone. */
  538. X        year = tp->tm_year;        /* Use to set up defaults */
  539. X        yday = tp->tm_yday;
  540. X        mon = tp->tm_mon;
  541. X        day = tp->tm_mday;
  542. X        hour = tp->tm_hour;
  543. X        min = tp->tm_min;
  544. X        if (localzone) {
  545. X            tp = localtime(&tres);
  546. X            zone =
  547. X            min - tp->tm_min + 60*(
  548. X                hour - tp->tm_hour + 24*(
  549. X                    /* If years differ, it's by one day. */
  550. X                        year - tp->tm_year
  551. X                    ?    year - tp->tm_year
  552. X                    :    yday - tp->tm_yday));
  553. X        }
  554. X        /* Adjust the default day, month and year according to zone.  */
  555. X        if ((min -= zone) < 0) {
  556. X            if (hour-(59-min)/60 < 0  &&  --day <= 0) {
  557. X            if (--mon < 0) {
  558. X                --year;
  559. X                mon = 11;
  560. X            }
  561. X            day  =  daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3));
  562. X            }
  563. X        } else
  564. X            if (
  565. X              24 <= hour+min/60  &&
  566. X              daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3))  <  ++day
  567. X            ) {
  568. X                if (11 < ++mon) {
  569. X                    ++year;
  570. X                    mon = 0;
  571. X                }
  572. X                day = 1;
  573. X            }
  574. X    }
  575. X    if (zone < -24*60  ||  24*60 < zone)
  576. X        return -1;
  577. X
  578. X
  579. X#ifdef DEBUG
  580. Xprintf("first YMD: %d %d %d\n",year,mon,day);
  581. X#endif
  582. X    tp = atm;
  583. X
  584. X    /* First must find date, using specified year, month, day.
  585. X     * If one of these is unspecified, it defaults either to the
  586. X     * current date (if no more global spec was given) or to the
  587. X     * zero-value for that spec (i.e. a more global spec was seen).
  588. X     * Reject times that do not fit in time_t,
  589. X     * without assuming that time_t is 32 bits or is signed.
  590. X     */
  591. X    if (given(tp->tm_year))
  592. X      {
  593. X        year = tp->tm_year;
  594. X        mon = 0;        /* Since year was given, default */
  595. X        day = 1;        /* for remaining specs is zero */
  596. X      }
  597. X    if (year < 69)            /* 1969/12/31 OK in some timezones.  */
  598. X        return -1;        /* ERR: year out of range */
  599. X    leap   =   !(year&3)  &&  (year%100 || !((year+300)%400));
  600. X    year -= 70;            /* UNIX time starts at 1970 */
  601. X
  602. X    /*
  603. X     * Find day of year.
  604. X     */
  605. X    {
  606. X        if (given(tp->tm_mon))
  607. X          {    mon = tp->tm_mon;    /* Month was specified */
  608. X            day = 1;        /* so set remaining default */
  609. X          }
  610. X        if (11 < (unsigned)mon)
  611. X            return -1;        /* ERR: bad month */
  612. X        if (given(tp->tm_mday)) day = tp->tm_mday;
  613. X        if(day < 1
  614. X         || (((daytb[mon+1]-daytb[mon]) < day)
  615. X            && (day!=29 || mon!=1 || !leap) ))
  616. X                return -1;    /* ERR: bad day */
  617. X        yday = daytb[mon]    /* Add # of days in months so far */
  618. X          + ((leap        /* Leap year, and past Feb?  If */
  619. X              && mon>1)? 1:0)    /* so, add leap day for this year */
  620. X          + day-1;        /* And finally add # days this mon */
  621. X
  622. X    }
  623. X    if (leap+365 <= (unsigned)yday)
  624. X        return -1;        /* ERR: bad YDAY */
  625. X
  626. X    if (year < 0) {
  627. X        if (yday != 364)
  628. X        return -1;        /* ERR: too early */
  629. X        t = -1;
  630. X    } else {
  631. X        tres = year*365;        /* Get # days of years so far */
  632. X        if (tres/365 != year)
  633. X            return -1;        /* ERR: overflow */
  634. X        t = tres
  635. X        + ((year+1)>>2)        /* plus # of leap days since 1970 */
  636. X        + yday;            /* and finally add # days this year */
  637. X        if (t+4 < tres)
  638. X            return -1;        /* ERR: overflow */
  639. X    }
  640. X    tres = t;
  641. X
  642. X    if (given(i = tp->tm_wday)) /* Check WDAY if present */
  643. X        if (i != (tres+4)%7)    /* 1970/01/01 was Thu = 4 */
  644. X            return -1;    /* ERR: bad WDAY */
  645. X
  646. X#ifdef DEBUG
  647. Xprintf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
  648. X#endif
  649. X    /*
  650. X     * Now determine time.  If not given, default to zeros
  651. X     * (since time is always the least global spec)
  652. X     */
  653. X    tres *= 86400L;            /* Get # seconds (24*60*60) */
  654. X    if (tres/86400L != t)
  655. X        return -1;        /* ERR: overflow */
  656. X    hour = min = sec = 0;
  657. X    if (given(tp->tm_hour)) hour = tp->tm_hour;
  658. X    if (given(tp->tm_min )) min  = tp->tm_min;
  659. X    if (given(tp->tm_sec )) sec  = tp->tm_sec;
  660. X    if (60 <= (unsigned)min  ||  60 < (unsigned)sec)
  661. X        return -1;        /* ERR: MS out of range */
  662. X    if (24 <= (unsigned)hour)
  663. X        if(hour != 24 || (min+sec) !=0)    /* Allow 24:00 */
  664. X            return -1;    /* ERR: H out of range */
  665. X
  666. X    t = tres;
  667. X    tres += sec + 60L*(zone + min + 60*hour);
  668. X
  669. X#ifdef DEBUG
  670. Xprintf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
  671. X#endif
  672. X
  673. X    if (!localzone)            /* check for overflow */
  674. X        return (year<0 ? (tres<0||86400L<=tres) : tres<t)  ?  -1  :  tres;
  675. X
  676. X    /* Check results; LT may have had a different GMT offset back then.  */
  677. X    tp = localtime(&tres);
  678. X    if (given(atm->tm_sec)  &&  atm->tm_sec != tp->tm_sec)
  679. X        return -1; /* If seconds don't match, we're in trouble.  */
  680. X    if (!(
  681. X        given(atm->tm_min)  &&  atm->tm_min != tp->tm_min  ||
  682. X        given(atm->tm_hour)  &&  atm->tm_hour != tp->tm_hour  ||
  683. X        given(atm->tm_mday)  &&  atm->tm_mday != tp->tm_mday  ||
  684. X        given(atm->tm_mon)  &&  atm->tm_mon != tp->tm_mon  ||
  685. X        given(atm->tm_year)  &&  atm->tm_year != tp->tm_year
  686. X    ))
  687. X        return tres; /* Everything matches.  */
  688. X
  689. X    } while (--attempts);
  690. X
  691. X    return -1;
  692. X}
  693. X
  694. X/*
  695. X* Convert Unix time to struct tm format.
  696. X* Use Coordinated Universal Time (UTC) if available and if version 5 or newer;
  697. X* use local time otherwise.
  698. X*/
  699. X    static const struct tm *
  700. Xtime2tm(unixtime)
  701. X    time_t unixtime;
  702. X{
  703. X    const struct tm *tm;
  704. X    return
  705. X            VERSION(5)<=RCSversion && (tm = gmtime(&unixtime))
  706. X        ?    tm
  707. X        :    localtime(&unixtime);
  708. X}
  709. X
  710. X/*
  711. X* Convert Unix time to RCS format.
  712. X* For compatibility with older versions of RCS,
  713. X* dates before AD 2000 are stored without the leading "19".
  714. X*/
  715. X    void
  716. Xtime2date(unixtime,date)
  717. X    time_t unixtime;
  718. X    char date[datesize];
  719. X{
  720. X    register const struct tm *tm = time2tm(unixtime);
  721. X    VOID sprintf(date, DATEFORM,
  722. X        tm->tm_year  +  (tm->tm_year<100 ? 0 : 1900),
  723. X        tm->tm_mon+1, tm->tm_mday,
  724. X        tm->tm_hour, tm->tm_min, tm->tm_sec
  725. X    );
  726. X}
  727. X
  728. X
  729. X
  730. X    void
  731. Xstr2date(source, target)
  732. X    const char *source;
  733. X    char target[datesize];
  734. X/* Parse a free-format date in SOURCE, convert it
  735. X * into RCS internal format, and store the result into TARGET.
  736. X */
  737. X{
  738. X    int zone;
  739. X    time_t unixtime;
  740. X    struct tm parseddate;
  741. X
  742. X    if (!partime(source, &parseddate, &zone))
  743. X        faterror("can't parse date/time: %s", source);
  744. X    if ((unixtime = maketime(&parseddate, zone))  ==  -1)
  745. X        faterror("bad date/time: %s", source);
  746. X    time2date(unixtime, target);
  747. X}
  748. END_OF_FILE
  749.   if test 8733 -ne `wc -c <'src/maketime.c'`; then
  750.     echo shar: \"'src/maketime.c'\" unpacked with wrong size!
  751.   fi
  752.   # end of 'src/maketime.c'
  753. fi
  754. if test -f 'src/rcsdiff.c' -a "${1}" != "-c" ; then 
  755.   echo shar: Will not clobber existing file \"'src/rcsdiff.c'\"
  756. else
  757.   echo shar: Extracting \"'src/rcsdiff.c'\" \(10976 characters\)
  758.   sed "s/^X//" >'src/rcsdiff.c' <<'END_OF_FILE'
  759. X/*
  760. X *                     RCS rcsdiff operation
  761. X */
  762. X/*****************************************************************************
  763. X *                       generate difference between RCS revisions
  764. X *****************************************************************************
  765. X */
  766. X
  767. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  768. X   Copyright 1990 by Paul Eggert
  769. X   Distributed under license by the Free Software Foundation, Inc.
  770. X
  771. XThis file is part of RCS.
  772. X
  773. XRCS is free software; you can redistribute it and/or modify
  774. Xit under the terms of the GNU General Public License as published by
  775. Xthe Free Software Foundation; either version 1, or (at your option)
  776. Xany later version.
  777. X
  778. XRCS is distributed in the hope that it will be useful,
  779. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  780. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  781. XGNU General Public License for more details.
  782. X
  783. XYou should have received a copy of the GNU General Public License
  784. Xalong with RCS; see the file COPYING.  If not, write to
  785. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  786. X
  787. XReport problems and direct all questions to:
  788. X
  789. X    rcs-bugs@cs.purdue.edu
  790. X
  791. X*/
  792. X
  793. X
  794. X
  795. X
  796. X/* $Log: rcsdiff.c,v $
  797. X * Revision 5.7  1990/12/13  06:54:07  eggert
  798. X * GNU diff 1.15 has -u.
  799. X *
  800. X * Revision 5.6  1990/11/01  05:03:39  eggert
  801. X * Remove unneeded setid check.
  802. X *
  803. X * Revision 5.5  1990/10/04  06:30:19  eggert
  804. X * Accumulate exit status across files.
  805. X *
  806. X * Revision 5.4  1990/09/27  01:31:43  eggert
  807. X * Yield 1, not EXIT_FAILURE, when diffs are found.
  808. X *
  809. X * Revision 5.3  1990/09/11  02:41:11  eggert
  810. X * Simplify -kkvl test.
  811. X *
  812. X * Revision 5.2  1990/09/04  17:07:19  eggert
  813. X * Diff's argv was too small by 1.
  814. X *
  815. X * Revision 5.1  1990/08/29  07:13:55  eggert
  816. X * Add -kkvl.
  817. X *
  818. X * Revision 5.0  1990/08/22  08:12:46  eggert
  819. X * Add -k, -V.  Don't use access().  Add setuid support.
  820. X * Remove compile-time limits; use malloc instead.
  821. X * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
  822. X * Add GNU diff's flags.  Make lock and temp files faster and safer.
  823. X * Ansify and Posixate.
  824. X *
  825. X * Revision 4.6  89/05/01  15:12:27  narten
  826. X * changed copyright header to reflect current distribution rules
  827. X * 
  828. X * Revision 4.5  88/08/09  19:12:41  eggert
  829. X * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
  830. X * 
  831. X * Revision 4.4  87/12/18  11:37:46  narten
  832. X * changes Jay Lepreau made in the 4.3 BSD version, to add support for
  833. X * "-i", "-w", and "-t" flags and to permit flags to be bundled together,
  834. X * merged in.
  835. X * 
  836. X * Revision 4.3  87/10/18  10:31:42  narten
  837. X * Updating version numbers. Changes relative to 1.1 actually
  838. X * relative to 4.1
  839. X * 
  840. X * Revision 1.3  87/09/24  13:59:21  narten
  841. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  842. X * warnings)
  843. X * 
  844. X * Revision 1.2  87/03/27  14:22:15  jenkins
  845. X * Port to suns
  846. X * 
  847. X * Revision 4.1  83/05/03  22:13:19  wft
  848. X * Added default branch, option -q, exit status like diff.
  849. X * Added fterror() to replace faterror().
  850. X * 
  851. X * Revision 3.6  83/01/15  17:52:40  wft
  852. X * Expanded mainprogram to handle multiple RCS files.
  853. X *
  854. X * Revision 3.5  83/01/06  09:33:45  wft
  855. X * Fixed passing of -c (context) option to diff.
  856. X *
  857. X * Revision 3.4  82/12/24  15:28:38  wft
  858. X * Added call to catchsig().
  859. X *
  860. X * Revision 3.3  82/12/10  16:08:17  wft
  861. X * Corrected checking of return code from diff; improved error msgs.
  862. X *
  863. X * Revision 3.2  82/12/04  13:20:09  wft
  864. X * replaced getdelta() with gettree(). Changed diagnostics.
  865. X *
  866. X * Revision 3.1  82/11/28  19:25:04  wft
  867. X * Initial revision.
  868. X *
  869. X */
  870. X#include "rcsbase.h"
  871. X
  872. X#if DIFF_L
  873. Xstatic const char *setup_label P((struct buf*,const char*,const char[datesize]));
  874. X#endif
  875. Xstatic void cleanup P((void));
  876. X
  877. Xstatic const char co[] = CO;
  878. X
  879. Xstatic int exitstatus;
  880. X
  881. XmainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.7 1990/12/13 06:54:07 eggert Exp $")
  882. X{
  883. X    static const char cmdusage[] =
  884. X        "\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ...";
  885. X    static const char quietarg[] = "-q";
  886. X
  887. X    int  revnums;                 /* counter for revision numbers given */
  888. X    const char *rev1, *rev2;    /* revision numbers from command line */
  889. X    const char *xrev1, *xrev2;    /* expanded revision numbers */
  890. X    const char *expandarg, *lexpandarg, *versionarg;
  891. X#if DIFF_L
  892. X    static struct buf labelbuf[2];
  893. X    int file_labels;
  894. X    const char **diff_label1, **diff_label2;
  895. X    char date2[datesize];
  896. X#endif
  897. X    const char **diffv, **diffp;    /* argv for subsidiary diff */
  898. X    const char **pp, *p, *diffvstr;
  899. X    struct buf commarg;
  900. X    struct buf numericrev;    /* expanded revision number */
  901. X    struct hshentries *gendeltas;    /* deltas to be generated */
  902. X    struct hshentry * target;
  903. X    int  exit_stats;
  904. X    char *argp, *dcp;
  905. X    register c;
  906. X
  907. X    initid();
  908. X    catchints();
  909. X
  910. X    bufautobegin(&commarg);
  911. X    bufautobegin(&numericrev);
  912. X    revnums = 0;
  913. X    rev1 = rev2 = xrev2 = nil;
  914. X#if DIFF_L
  915. X    file_labels = 0;
  916. X#endif
  917. X    expandarg = versionarg = quietarg; /* i.e. a no-op */
  918. X
  919. X    /* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null.  */
  920. X    diffp = diffv = tnalloc(const char*, argc + 4 + 2*DIFF_L);
  921. X    *diffp++ = nil;
  922. X    *diffp++ = nil;
  923. X    *diffp++ = DIFF;
  924. X
  925. X    while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
  926. X    dcp = argp = *argv + 1;
  927. X    while (c = *argp++) switch (c) {
  928. X        case 'r':
  929. X            if (*argp!='\0') {
  930. X            if (revnums==0) {
  931. X                rev1= argp; revnums=1;
  932. X            } else if (revnums==1) {
  933. X                rev2= argp; revnums=2;
  934. X            } else {
  935. X                faterror("too many revision numbers");
  936. X            }
  937. X            } /* do nothing for empty -r */
  938. X            goto option_handled;
  939. X#if DIFF_L
  940. X        case 'L':
  941. X            if (++file_labels == 2)
  942. X            faterror("too many -L options");
  943. X            /* fall into */
  944. X#endif
  945. X        case 'C': case 'D': case 'F': case 'I':
  946. X            *dcp++ = c;
  947. X            if (*argp)
  948. X            do *dcp++ = *argp;
  949. X            while (*++argp);
  950. X            else {
  951. X            if (!--argc)
  952. X                faterror("-%c needs following argument%s",
  953. X                    c, cmdusage
  954. X                );
  955. X            *diffp++ = *argv++;
  956. X            }
  957. X            break;
  958. X        case 'B': case 'H': case 'T':
  959. X        case '0': case '1': case '2': case '3': case '4':
  960. X        case '5': case '6': case '7': case '8': case '9':
  961. X        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  962. X        case 'h': case 'i': case 'n': case 'p':
  963. X        case 't': case 'u': case 'w':
  964. X            *dcp++ = c;
  965. X            break;
  966. X        case 'q':
  967. X            quietflag=true;
  968. X            break;
  969. X        case 'V':
  970. X            versionarg = *argv;
  971. X            setRCSversion(versionarg);
  972. X            goto option_handled;
  973. X        case 'k':
  974. X            expandarg = *argv;
  975. X            if (0 <= str2expmode(expandarg+2))
  976. X            goto option_handled;
  977. X            /* fall into */
  978. X        default:
  979. X            faterror("unknown option: %s%s", *argv, cmdusage);
  980. X        };
  981. X      option_handled:
  982. X    if (dcp != *argv+1) {
  983. X        *dcp = 0;
  984. X        *diffp++ = *argv;
  985. X    }
  986. X    } /* end of option processing */
  987. X
  988. X    if (argc<1) faterror("no input file%s", cmdusage);
  989. X
  990. X    for (pp = diffv+3, c = 0;  pp<diffp;  )
  991. X        c += strlen(*pp++) + 1;
  992. X    diffvstr = argp = tnalloc(char, c + 1);
  993. X    for (pp = diffv+3;  pp<diffp;  ) {
  994. X        p = *pp++;
  995. X        *argp++ = ' ';
  996. X        while ((*argp = *p++))
  997. X            argp++;
  998. X    }
  999. X    *argp = 0;
  1000. X
  1001. X#if DIFF_L
  1002. X    diff_label1 = diff_label2 = nil;
  1003. X    if (file_labels < 2) {
  1004. X        if (!file_labels)
  1005. X            diff_label1 = diffp++;
  1006. X        diff_label2 = diffp++;
  1007. X    }
  1008. X#endif
  1009. X    diffp[2] = nil;
  1010. X
  1011. X    /* now handle all filenames */
  1012. X    do {
  1013. X        finptr=NULL;
  1014. X        ffree();
  1015. X
  1016. X        if (pairfilenames(argc, argv, rcsreadopen, true, false) != 1)
  1017. X            continue;
  1018. X        diagnose("===================================================================\nRCS file: %s\n",RCSfilename);
  1019. X        if (!rev2) {
  1020. X        /* Make sure work file is readable, and get its status.  */
  1021. X        if ((c = open(workfilename,O_RDONLY,0)) < 0) {
  1022. X            eerror(workfilename);
  1023. X            continue;
  1024. X        }
  1025. X        if (!getfworkstat(c)) continue;
  1026. X        VOID close(c);
  1027. X        }
  1028. X
  1029. X
  1030. X        gettree(); /* reads in the delta tree */
  1031. X
  1032. X        if (Head==nil) {
  1033. X            error("no revisions present");
  1034. X            continue;
  1035. X        }
  1036. X        if (revnums==0)
  1037. X            rev1  =  Dbranch ? Dbranch : Head->num;
  1038. X
  1039. X        if (!expandsym(rev1,&numericrev)) continue;
  1040. X        if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
  1041. X        xrev1=target->num;
  1042. X#if DIFF_L
  1043. X        if (diff_label1)
  1044. X        *diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
  1045. X#endif
  1046. X
  1047. X        lexpandarg = expandarg;
  1048. X        if (revnums==2) {
  1049. X            if (!expandsym(rev2, &numericrev)) continue;
  1050. X            if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
  1051. X            xrev2=target->num;
  1052. X        } else if (
  1053. X            target->lockedby
  1054. X        &&    lexpandarg == quietarg
  1055. X        &&    Expand == KEYVAL_EXPAND
  1056. X        &&    WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
  1057. X        )
  1058. X            lexpandarg = "-kkvl";
  1059. X#if DIFF_L
  1060. X        if (diff_label2)
  1061. X        if (revnums == 2)
  1062. X            *diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
  1063. X        else {
  1064. X            time2date(workstat.st_mtime, date2);
  1065. X            *diff_label2 = setup_label(&labelbuf[1], workfilename, date2);
  1066. X        }
  1067. X#endif
  1068. X
  1069. X        diffp[0] = maketemp(0);
  1070. X        diagnose("retrieving revision %s\n", xrev1);
  1071. X        bufscpy(&commarg, "-p");
  1072. X        bufscat(&commarg, xrev1);
  1073. X        if (run((char*)nil,diffp[0], co,quietarg,commarg.string,lexpandarg,versionarg,RCSfilename,(char*)nil)){
  1074. X            error("co failed");
  1075. X            continue;
  1076. X        }
  1077. X        if (!rev2) {
  1078. X            diffp[1] = workfilename;
  1079. X            if (workfilename[0] == '+') {
  1080. X                /* Some diffs have options with leading '+'. */
  1081. X                diffp[1] = argp =
  1082. X                    ftnalloc(char, strlen(workfilename)+3);
  1083. X                *argp++ = '.';
  1084. X                *argp++ = SLASH;
  1085. X                VOID strcpy(argp, workfilename);
  1086. X            }
  1087. X        } else {
  1088. X            diffp[1] = maketemp(1);
  1089. X            diagnose("retrieving revision %s\n",xrev2);
  1090. X            bufscpy(&commarg, "-p");
  1091. X            bufscat(&commarg, xrev2);
  1092. X            if (run((char*)nil,diffp[1], co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char *)nil)){
  1093. X                error("co failed");
  1094. X                continue;
  1095. X            }
  1096. X        }
  1097. X        if (!rev2)
  1098. X            diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename);
  1099. X        else
  1100. X            diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
  1101. X
  1102. X        exit_stats = runv(diffv);
  1103. X
  1104. X        if (exit_stats)
  1105. X            if (WIFEXITED(exit_stats) && WEXITSTATUS(exit_stats)==1) {
  1106. X                if (!exitstatus)
  1107. X                    exitstatus = 1;
  1108. X            } else
  1109. X                error("diff failed");
  1110. X    } while (cleanup(),
  1111. X         ++argv, --argc >=1);
  1112. X
  1113. X
  1114. X    tempunlink();
  1115. X    exitmain(exitstatus);
  1116. X}
  1117. X
  1118. X    static void
  1119. Xcleanup()
  1120. X{
  1121. X    if (nerror) exitstatus = EXIT_TROUBLE;
  1122. X    if (finptr) ffclose(finptr);
  1123. X}
  1124. X
  1125. X#if lint
  1126. X#    define exiterr rdiffExit
  1127. X#endif
  1128. X    exiting void
  1129. Xexiterr()
  1130. X{
  1131. X    tempunlink();
  1132. X    _exit(EXIT_TROUBLE);
  1133. X}
  1134. X
  1135. X#if DIFF_L
  1136. X    static const char *
  1137. Xsetup_label(b, name, date)
  1138. X    struct buf *b;
  1139. X    const char *name;
  1140. X    const char date[datesize];
  1141. X{
  1142. X    const char *p;
  1143. X
  1144. X    bufalloc(b,  2+strlen(name)+1+datesize);
  1145. X    for (p = date;  *p++ != '.';  )
  1146. X        ;
  1147. X    VOID sprintf(b->string, "-L%s\t%s%.*s/%.2s/%.2s %.2s:%.2s:%s",
  1148. X        name,
  1149. X        date[2]=='.' ? "19" : "",
  1150. X        p-date-1, date, p, p+3, p+6, p+9, p+12
  1151. X    );
  1152. X    return b->string;
  1153. X}
  1154. X#endif
  1155. END_OF_FILE
  1156.   if test 10976 -ne `wc -c <'src/rcsdiff.c'`; then
  1157.     echo shar: \"'src/rcsdiff.c'\" unpacked with wrong size!
  1158.   fi
  1159.   # end of 'src/rcsdiff.c'
  1160. fi
  1161. if test -f 'src/rcskeep.c' -a "${1}" != "-c" ; then 
  1162.   echo shar: Will not clobber existing file \"'src/rcskeep.c'\"
  1163. else
  1164.   echo shar: Extracting \"'src/rcskeep.c'\" \(9239 characters\)
  1165.   sed "s/^X//" >'src/rcskeep.c' <<'END_OF_FILE'
  1166. X/*
  1167. X *                     RCS keyword extraction
  1168. X */
  1169. X/*****************************************************************************
  1170. X *                       main routine: getoldkeys()
  1171. X *                       Testprogram: define KEEPTEST
  1172. X *****************************************************************************
  1173. X */
  1174. X
  1175. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1176. X   Copyright 1990 by Paul Eggert
  1177. X   Distributed under license by the Free Software Foundation, Inc.
  1178. X
  1179. XThis file is part of RCS.
  1180. X
  1181. XRCS is free software; you can redistribute it and/or modify
  1182. Xit under the terms of the GNU General Public License as published by
  1183. Xthe Free Software Foundation; either version 1, or (at your option)
  1184. Xany later version.
  1185. X
  1186. XRCS is distributed in the hope that it will be useful,
  1187. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1188. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1189. XGNU General Public License for more details.
  1190. X
  1191. XYou should have received a copy of the GNU General Public License
  1192. Xalong with RCS; see the file COPYING.  If not, write to
  1193. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1194. X
  1195. XReport problems and direct all questions to:
  1196. X
  1197. X    rcs-bugs@cs.purdue.edu
  1198. X
  1199. X*/
  1200. X
  1201. X
  1202. X
  1203. X/* $Log: rcskeep.c,v $
  1204. X * Revision 5.2  1990/10/04  06:30:20  eggert
  1205. X * Parse time zone offsets; future RCS versions may output them.
  1206. X *
  1207. X * Revision 5.1  1990/09/20  02:38:56  eggert
  1208. X * ci -k now checks dates more thoroughly.
  1209. X *
  1210. X * Revision 5.0  1990/08/22  08:12:53  eggert
  1211. X * Retrieve old log message if there is one.
  1212. X * Don't require final newline.
  1213. X * Remove compile-time limits; use malloc instead.  Tune.
  1214. X * Permit dates past 1999/12/31.  Ansify and Posixate.
  1215. X *
  1216. X * Revision 4.6  89/05/01  15:12:56  narten
  1217. X * changed copyright header to reflect current distribution rules
  1218. X * 
  1219. X * Revision 4.5  88/08/09  19:13:03  eggert
  1220. X * Remove lint and speed up by making FILE *fp local, not global.
  1221. X * 
  1222. X * Revision 4.4  87/12/18  11:44:21  narten
  1223. X * more lint cleanups (Guy Harris)
  1224. X * 
  1225. X * Revision 4.3  87/10/18  10:35:50  narten
  1226. X * Updating version numbers. Changes relative to 1.1 actually relative
  1227. X * to 4.1
  1228. X * 
  1229. X * Revision 1.3  87/09/24  14:00:00  narten
  1230. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1231. X * warnings)
  1232. X * 
  1233. X * Revision 1.2  87/03/27  14:22:29  jenkins
  1234. X * Port to suns
  1235. X * 
  1236. X * Revision 4.1  83/05/10  16:26:44  wft
  1237. X * Added new markers Id and RCSfile; extraction added.
  1238. X * Marker matching with trymatch().
  1239. X * 
  1240. X * Revision 3.2  82/12/24  12:08:26  wft
  1241. X * added missing #endif.
  1242. X *
  1243. X * Revision 3.1  82/12/04  13:22:41  wft
  1244. X * Initial revision.
  1245. X *
  1246. X */
  1247. X
  1248. X/*
  1249. X#define KEEPTEST
  1250. X*/
  1251. X/* Testprogram; prints out the keyword values found. */
  1252. X
  1253. X#include  "rcsbase.h"
  1254. X
  1255. XlibId(keepId, "$Id: rcskeep.c,v 5.2 1990/10/04 06:30:20 eggert Exp $")
  1256. X
  1257. Xstatic int checknum P((const char*,int));
  1258. Xstatic int getprevdate P((FILE*));
  1259. Xstatic int getprevid P((int,FILE*,struct buf*));
  1260. Xstatic int getprevrev P((FILE*));
  1261. Xstatic int getval P((FILE*,struct buf*,int));
  1262. Xstatic int get0val P((int,FILE*,struct buf*,int));
  1263. X
  1264. Xstruct buf prevauthor, prevrev, prevstate;
  1265. Xchar prevdate[datesize];
  1266. X
  1267. X    int
  1268. Xgetoldkeys(fp)
  1269. X    register FILE *fp;
  1270. X/* Function: Tries to read keyword values for author, date,
  1271. X * revision number, and state out of the file fp.
  1272. X * The results are placed into
  1273. X * prevauthor, prevdate, prevrev, prevstate.
  1274. X * Aborts immediately if it finds an error and returns false.
  1275. X * If it returns true, it doesn't mean that any of the
  1276. X * values were found; instead, check to see whether the corresponding arrays
  1277. X * contain the empty string.
  1278. X */
  1279. X{
  1280. X    register int c;
  1281. X    char keyword[keylength+1];
  1282. X    register char * tp;
  1283. X
  1284. X    /* initialize to empty */
  1285. X    bufscpy(&prevauthor, "");
  1286. X    bufscpy(&prevrev, "");
  1287. X    bufscpy(&prevstate, "");
  1288. X    *prevdate = 0;
  1289. X
  1290. X    while( (c=getc(fp)) != EOF) {
  1291. X        if ( c==KDELIM) {
  1292. X        do {
  1293. X        /* try to get keyword */
  1294. X        tp = keyword;
  1295. X        while ((c=getc(fp))!=EOF && c!='\n' && c!=KDELIM && c!=VDELIM 
  1296. X               && tp<keyword+keylength
  1297. X        )
  1298. X            *tp++ = c;
  1299. X        } while (c==KDELIM);
  1300. X        if (c==EOF)
  1301. X        break;
  1302. X            if (c!=VDELIM) continue;
  1303. X        *tp = c;
  1304. X        if ((c=getc(fp))!=' ' && c!='\t')
  1305. X        continue;
  1306. X
  1307. X        switch (trymatch(keyword)) {
  1308. X            case Author:
  1309. X        if (!getprevid(0, fp, &prevauthor))
  1310. X            return false;
  1311. X        c = getc(fp);
  1312. X                break;
  1313. X            case Date:
  1314. X        if (!(c = getprevdate(fp)))
  1315. X            return false;
  1316. X                break;
  1317. X            case Header:
  1318. X            case Id:
  1319. X        if (!(
  1320. X              getval(fp, (struct buf*)nil, false) &&
  1321. X              getprevrev(fp) &&
  1322. X              (c = getprevdate(fp)) &&
  1323. X              getprevid(c, fp, &prevauthor) &&
  1324. X              getprevid(0, fp, &prevstate)
  1325. X        ))
  1326. X            return false;
  1327. X        /* Skip either ``who'' (new form) or ``Locker: who'' (old).  */
  1328. X        if (getval(fp, (struct buf*)nil, true) &&
  1329. X            getval(fp, (struct buf*)nil, true))
  1330. X            c = getc(fp);
  1331. X        else if (nerror)
  1332. X            return false;
  1333. X        else
  1334. X            c = KDELIM;
  1335. X        break;
  1336. X            case Locker:
  1337. X            case Log:
  1338. X            case RCSfile:
  1339. X            case Source:
  1340. X        if (!getval(fp, (struct buf*)nil, false))
  1341. X            return false;
  1342. X        c = getc(fp);
  1343. X                break;
  1344. X            case Revision:
  1345. X        if (!getprevrev(fp))
  1346. X            return false;
  1347. X        c = getc(fp);
  1348. X                break;
  1349. X            case State:
  1350. X        if (!getprevid(0, fp, &prevstate))
  1351. X            return false;
  1352. X        c = getc(fp);
  1353. X                break;
  1354. X            default:
  1355. X               continue;
  1356. X            }
  1357. X        if (c != KDELIM) {
  1358. X        error("closing %c missing on keyword", KDELIM);
  1359. X        return false;
  1360. X        }
  1361. X        if (*prevauthor.string && *prevdate && *prevrev.string && *prevstate.string) {
  1362. X                break;
  1363. X           }
  1364. X        }
  1365. X    }
  1366. X
  1367. X    arewind(fp);
  1368. X    return true;
  1369. X}
  1370. X
  1371. X
  1372. X    static int
  1373. Xgetval(fp, target, optional)
  1374. X    register FILE *fp;
  1375. X    struct buf *target;
  1376. X    int optional;
  1377. X/* Reads a keyword value from FP into TARGET.
  1378. X * Returns true if one is found, false otherwise.
  1379. X * Does not modify target if it is nil.
  1380. X * Do not report an error if OPTIONAL is set and KDELIM is found instead.
  1381. X */
  1382. X{
  1383. X    return get0val(getc(fp), fp, target, optional);
  1384. X}
  1385. X
  1386. X    static int
  1387. Xget0val(c, fp, target, optional)
  1388. X    register int c;
  1389. X    register FILE *fp;
  1390. X    struct buf *target;
  1391. X    int optional;
  1392. X/* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
  1393. X * Same as getval, except C is the lookahead character.
  1394. X */
  1395. X{   register char * tp;
  1396. X    const char *tlim;
  1397. X    register int got1;
  1398. X
  1399. X    if (target) {
  1400. X    bufalloc(target, 1);
  1401. X    tp = target->string;
  1402. X    tlim = tp + target->size;
  1403. X    } else
  1404. X    tlim = tp = 0;
  1405. X    got1 = false;
  1406. X    for (;;  c = getc(fp))
  1407. X    switch (c) {
  1408. X        default:
  1409. X        got1 = true;
  1410. X        if (tp) {
  1411. X            *tp++ = c;
  1412. X            if (tlim <= tp)
  1413. X            tp = bufenlarge(target, &tlim);
  1414. X        }
  1415. X        continue;
  1416. X
  1417. X        case ' ':
  1418. X        case '\t':
  1419. X        if (tp) {
  1420. X            *tp = 0;
  1421. X#            ifdef KEEPTEST
  1422. X            VOID printf("getval: %s\n", target);
  1423. X#            endif
  1424. X        }
  1425. X        if (!got1)
  1426. X            error("too much white space in keyword value");
  1427. X        return got1;
  1428. X
  1429. X        case KDELIM:
  1430. X        if (!got1 && optional)
  1431. X            return false;
  1432. X        /* fall into */
  1433. X        case '\n':
  1434. X        case 0:
  1435. X        case EOF:
  1436. X        error("badly terminated keyword value");
  1437. X        return false;
  1438. X    }
  1439. X}
  1440. X
  1441. X
  1442. X    static int
  1443. Xgetprevdate(fp)
  1444. XFILE *fp;
  1445. X/* Function: reads a date prevdate; checks format
  1446. X * Return 0 on error, lookahead character otherwise.
  1447. X */
  1448. X{
  1449. X    struct buf prevday, prevtime, prevzone, prev;
  1450. X    register const char *p;
  1451. X    register int c;
  1452. X
  1453. X    c = 0;
  1454. X    bufautobegin(&prevday);
  1455. X    if (getval(fp,&prevday,false)) {
  1456. X    bufautobegin(&prevtime);
  1457. X    if (getval(fp,&prevtime,false)) {
  1458. X        bufautobegin(&prevzone);
  1459. X        bufscpy(&prevzone, "");
  1460. X        c = getc(fp);
  1461. X        if (c=='-' || c=='+')
  1462. X        c = get0val(c,fp,&prevzone,false) ? getc(fp) : 0;
  1463. X        if (c) {
  1464. X        bufautobegin(&prev);
  1465. X        p = prevday.string;
  1466. X        bufalloc(&prev, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5);
  1467. X        VOID sprintf(prev.string, "%s%s %s %s", 
  1468. X            /* Parse dates put out by old versions of RCS.  */
  1469. X            isdigit(p[0]) && isdigit(p[1]) && p[2]=='/'  ?  "19"  :  "",
  1470. X            p, prevtime.string, prevzone.string
  1471. X        );
  1472. X        str2date(prev.string, prevdate);
  1473. X        bufautoend(&prev);
  1474. X        }
  1475. X        bufautoend(&prevzone);
  1476. X    }
  1477. X    bufautoend(&prevtime);
  1478. X    }
  1479. X    bufautoend(&prevday);
  1480. X    return c;
  1481. X}
  1482. X
  1483. X    static int
  1484. Xgetprevid(c, fp, b)
  1485. X    int c;
  1486. X    FILE *fp;
  1487. X    struct buf *b;
  1488. X/* Get previous identifier from C+FP into B.  */
  1489. X{
  1490. X    if (!get0val(c?c:getc(fp), fp, b, false))
  1491. X        return false;
  1492. X    checksid(b->string);
  1493. X    return true;
  1494. X}
  1495. X
  1496. X    static int
  1497. Xgetprevrev(fp)
  1498. X    FILE *fp;
  1499. X/* Get previous revision from FP into prevrev.  */
  1500. X{
  1501. X    return getval(fp,&prevrev,false) && checknum(prevrev.string,-1);
  1502. X}
  1503. X
  1504. X
  1505. X    static int
  1506. Xchecknum(sp,fields)
  1507. X    register const char *sp;
  1508. X    int fields;
  1509. X{    register int dotcount;
  1510. X     dotcount=0;
  1511. X     while(*sp) {
  1512. X        if (*sp=='.') dotcount++;
  1513. X    else if (!isdigit(*sp)) return false;
  1514. X        sp++;
  1515. X     }
  1516. X     return fields<0 ? dotcount&1 : dotcount==fields;
  1517. X}
  1518. X
  1519. X
  1520. X
  1521. X#ifdef KEEPTEST
  1522. X
  1523. Xconst char cmdid[] ="keeptest";
  1524. X
  1525. X    int
  1526. Xmain(argc, argv)
  1527. Xint  argc; char  *argv[];
  1528. X{
  1529. X        while (*(++argv)) {
  1530. X        FILE *f;
  1531. X        if (!(f = fopen(*argv,"r"))) {
  1532. X            perror(f);
  1533. X            exit(1);
  1534. X        }
  1535. X        getoldkeys(f);
  1536. X        VOID fclose(f);
  1537. X                VOID printf("%s:  revision: %s, date: %s, author: %s, state: %s\n",
  1538. X                *argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string);
  1539. X    }
  1540. X    exitmain(EXIT_SUCCESS);
  1541. X}
  1542. X#endif
  1543. END_OF_FILE
  1544.   if test 9239 -ne `wc -c <'src/rcskeep.c'`; then
  1545.     echo shar: \"'src/rcskeep.c'\" unpacked with wrong size!
  1546.   fi
  1547.   # end of 'src/rcskeep.c'
  1548. fi
  1549. if test -f 'src/rcsmerge.c' -a "${1}" != "-c" ; then 
  1550.   echo shar: Will not clobber existing file \"'src/rcsmerge.c'\"
  1551. else
  1552.   echo shar: Extracting \"'src/rcsmerge.c'\" \(7291 characters\)
  1553.   sed "s/^X//" >'src/rcsmerge.c' <<'END_OF_FILE'
  1554. X/*
  1555. X *                       rcsmerge operation
  1556. X */
  1557. X/*****************************************************************************
  1558. X *                       join 2 revisions with respect to a third
  1559. X *****************************************************************************
  1560. X */
  1561. X
  1562. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  1563. X   Copyright 1990 by Paul Eggert
  1564. X   Distributed under license by the Free Software Foundation, Inc.
  1565. X
  1566. XThis file is part of RCS.
  1567. X
  1568. XRCS is free software; you can redistribute it and/or modify
  1569. Xit under the terms of the GNU General Public License as published by
  1570. Xthe Free Software Foundation; either version 1, or (at your option)
  1571. Xany later version.
  1572. X
  1573. XRCS is distributed in the hope that it will be useful,
  1574. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1575. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1576. XGNU General Public License for more details.
  1577. X
  1578. XYou should have received a copy of the GNU General Public License
  1579. Xalong with RCS; see the file COPYING.  If not, write to
  1580. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1581. X
  1582. XReport problems and direct all questions to:
  1583. X
  1584. X    rcs-bugs@cs.purdue.edu
  1585. X
  1586. X*/
  1587. X
  1588. X
  1589. X
  1590. X/* $Log: rcsmerge.c,v $
  1591. X * Revision 5.3  1990/11/01  05:03:50  eggert
  1592. X * Remove unneeded setid check.
  1593. X *
  1594. X * Revision 5.2  1990/09/04  08:02:28  eggert
  1595. X * Check for I/O error when reading working file.
  1596. X *
  1597. X * Revision 5.1  1990/08/29  07:14:04  eggert
  1598. X * Add -q.  Pass -L options to merge.
  1599. X *
  1600. X * Revision 5.0  1990/08/22  08:13:41  eggert
  1601. X * Propagate merge's exit status.
  1602. X * Remove compile-time limits; use malloc instead.
  1603. X * Make lock and temp files faster and safer.  Ansify and Posixate.  Add -V.
  1604. X * Don't use access().  Tune.
  1605. X *
  1606. X * Revision 4.5  89/05/01  15:13:16  narten
  1607. X * changed copyright header to reflect current distribution rules
  1608. X * 
  1609. X * Revision 4.4  88/08/09  19:13:13  eggert
  1610. X * Beware merging into a readonly file.
  1611. X * Beware merging a revision to itself (no change).
  1612. X * Use execv(), not system(); yield exit status like diff(1)'s.
  1613. X * 
  1614. X * Revision 4.3  87/10/18  10:38:02  narten
  1615. X * Updating version numbers. Changes relative to version 1.1 
  1616. X * actually relative to 4.1
  1617. X * 
  1618. X * Revision 1.3  87/09/24  14:00:31  narten
  1619. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  1620. X * warnings)
  1621. X * 
  1622. X * Revision 1.2  87/03/27  14:22:36  jenkins
  1623. X * Port to suns
  1624. X * 
  1625. X * Revision 4.1  83/03/28  11:14:57  wft
  1626. X * Added handling of default branch.
  1627. X * 
  1628. X * Revision 3.3  82/12/24  15:29:00  wft
  1629. X * Added call to catchsig().
  1630. X *
  1631. X * Revision 3.2  82/12/10  21:32:02  wft
  1632. X * Replaced getdelta() with gettree(); improved error messages.
  1633. X *
  1634. X * Revision 3.1  82/11/28  19:27:44  wft
  1635. X * Initial revision.
  1636. X *
  1637. X */
  1638. X#include "rcsbase.h"
  1639. X
  1640. Xstatic exiting void nowork P((void));
  1641. X
  1642. Xstatic const char co[] = CO;
  1643. X
  1644. XmainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.3 1990/11/01 05:03:50 eggert Exp $")
  1645. X{
  1646. X    static const char cmdusage[] =
  1647. X        "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file";
  1648. X    static const char quietarg[] = "-q";
  1649. X
  1650. X    const char *rev1, *rev2; /*revision numbers*/
  1651. X    const char *temp1file, *temp2file;
  1652. X    const char *expandarg, *versionarg;
  1653. X    const char *mergearg[13], **a;
  1654. X        int tostdout;
  1655. X    int status, workfd;
  1656. X    struct buf commarg;
  1657. X    struct buf numericrev; /* holds expanded revision number */
  1658. X    struct hshentries *gendeltas; /* deltas to be generated */
  1659. X        struct hshentry * target;
  1660. X
  1661. X    initid();
  1662. X        catchints();
  1663. X
  1664. X    bufautobegin(&commarg);
  1665. X    bufautobegin(&numericrev);
  1666. X    rev1 = rev2 = nil;
  1667. X    status = 0; /* Keep lint happy.  */
  1668. X    tostdout = false;
  1669. X    expandarg = versionarg = quietarg; /* i.e. a no-op */
  1670. X
  1671. X        while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
  1672. X                switch ((*argv)[1]) {
  1673. X                case 'p':
  1674. X                        tostdout=true;
  1675. X            goto revno;
  1676. X        case 'q':
  1677. X            quietflag = true;
  1678. X                        /* falls into -r */
  1679. X                case 'r':
  1680. X        revno:
  1681. X                        if ((*argv)[2]!='\0') {
  1682. X                if (!rev1)
  1683. X                    rev1 = *argv + 2;
  1684. X                else if (!rev2)
  1685. X                    rev2 = *argv + 2;
  1686. X                else
  1687. X                                    faterror("too many revision numbers");
  1688. X                        } /* do nothing for empty -r or -p */
  1689. X                        break;
  1690. X        case 'V':
  1691. X            versionarg = *argv;
  1692. X            setRCSversion(versionarg);
  1693. X            break;
  1694. X
  1695. X        case 'k':
  1696. X            expandarg = *argv;
  1697. X            if (0 <= str2expmode(expandarg+2))
  1698. X                break;
  1699. X            /* fall into */
  1700. X                default:
  1701. X            faterror("unknown option: %s%s", *argv, cmdusage);
  1702. X                };
  1703. X        } /* end of option processing */
  1704. X
  1705. X    if (argc<1) faterror("no input file%s", cmdusage);
  1706. X    if (!rev1) faterror("no base revision number given");
  1707. X
  1708. X        /* now handle all filenames */
  1709. X
  1710. X    if (pairfilenames(argc, argv, rcsreadopen, true, false) == 1) {
  1711. X
  1712. X                if (argc>2 || (argc==2&&argv[1]!=nil))
  1713. X                        warn("too many arguments");
  1714. X        diagnose("RCS file: %s\n", RCSfilename);
  1715. X        if ((workfd = open(workfilename, tostdout?O_RDONLY:O_RDWR)) < 0)
  1716. X            nowork();
  1717. X
  1718. X                gettree();  /* reads in the delta tree */
  1719. X
  1720. X                if (Head==nil) faterror("no revisions present");
  1721. X
  1722. X
  1723. X        if (!expandsym(rev1,&numericrev)) goto end;
  1724. X        if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
  1725. X                rev1=target->num;
  1726. X        if (!rev2)
  1727. X            rev2  =  Dbranch ? Dbranch : Head->num;
  1728. X        if (!expandsym(rev2,&numericrev)) goto end;
  1729. X        if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
  1730. X                rev2=target->num;
  1731. X
  1732. X        if (strcmp(rev1,rev2) == 0) {
  1733. X            error("merging revision %s to itself (no change)",
  1734. X                rev1
  1735. X            );
  1736. X            if (tostdout) {
  1737. X                FILE *w;
  1738. X                errno = 0;
  1739. X                if (!(w = fdopen(workfd,"r")))
  1740. X                    nowork();
  1741. X                fastcopy(w,stdout);
  1742. X                ffclose(w);
  1743. X            }
  1744. X            goto end;
  1745. X        }
  1746. X        if (close(workfd) < 0)
  1747. X            nowork();
  1748. X
  1749. X        temp1file = maketemp(0);
  1750. X        temp2file = maketemp(1);
  1751. X
  1752. X        diagnose("retrieving revision %s\n", rev1);
  1753. X        bufscpy(&commarg, "-p");
  1754. X        bufscat(&commarg, rev1);
  1755. X        if (run((char*)nil,temp1file, co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char*)nil)){
  1756. X                        faterror("co failed");
  1757. X                }
  1758. X        diagnose("retrieving revision %s\n",rev2);
  1759. X        bufscpy(&commarg, "-p");
  1760. X        bufscat(&commarg, rev2);
  1761. X        if (run((char*)nil,temp2file, co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char*)nil)){
  1762. X                        faterror("co failed");
  1763. X                }
  1764. X        diagnose("Merging differences between %s and %s into %s%s\n",
  1765. X                         rev1, rev2, workfilename,
  1766. X                         tostdout?"; result to stdout":"");
  1767. X
  1768. X        a = mergearg;
  1769. X        *a++ = nil;
  1770. X        *a++ = nil;
  1771. X        *a++ = MERGE;
  1772. X        if (tostdout)
  1773. X            *a++ = "-p";
  1774. X        if (quietflag)
  1775. X            *a++ = quietarg;
  1776. X        *a++ = "-L";  *a++ = workfilename;
  1777. X        *a++ = "-L";  *a++ = rev2;
  1778. X        *a++ = workfilename;
  1779. X        *a++ = temp1file;
  1780. X        *a++ = temp2file;
  1781. X        *a = nil;
  1782. X
  1783. X        status = runv(mergearg);
  1784. X        if (!WIFEXITED(status)  ||  1 < WEXITSTATUS(status)) {
  1785. X                        faterror("merge failed");
  1786. X                }
  1787. X        }
  1788. X
  1789. Xend:
  1790. X    tempunlink();
  1791. X    exitmain(nerror ? EXIT_TROUBLE : WEXITSTATUS(status));
  1792. X}
  1793. X
  1794. X#if lint
  1795. X#    define exiterr rmergeExit
  1796. X#endif
  1797. X    exiting void
  1798. Xexiterr()
  1799. X{
  1800. X    tempunlink();
  1801. X    _exit(EXIT_TROUBLE);
  1802. X}
  1803. X
  1804. X
  1805. X    static exiting void
  1806. Xnowork()
  1807. X{
  1808. X    efaterror(workfilename);
  1809. X}
  1810. END_OF_FILE
  1811.   if test 7291 -ne `wc -c <'src/rcsmerge.c'`; then
  1812.     echo shar: \"'src/rcsmerge.c'\" unpacked with wrong size!
  1813.   fi
  1814.   # end of 'src/rcsmerge.c'
  1815. fi
  1816. echo shar: End of archive 10 \(of 12\).
  1817. cp /dev/null ark10isdone
  1818. MISSING=""
  1819. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1820.     if test ! -f ark${I}isdone ; then
  1821.     MISSING="${MISSING} ${I}"
  1822.     fi
  1823. done
  1824. if test "${MISSING}" = "" ; then
  1825.     echo You have unpacked all 12 archives.
  1826.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1827. else
  1828.     echo You still must unpack the following archives:
  1829.     echo "        " ${MISSING}
  1830. fi
  1831. exit 0
  1832. exit 0 # Just in case...
  1833.